#pragma once
#include"Mutex.hpp"

template<class T,size_t maxsize = 10>
class RingQueue
{
public:
    RingQueue()
    {
        _rq.resize(maxsize);
        sem_init(&_consumer_sem,0,0);
        sem_init(&_productor_sem,0,maxsize);
        _consumer_index=0;
        _productor_index=0;
        pthread_mutex_init(&_productor_mutex,nullptr);
        pthread_mutex_init(&_consumer_mutex,nullptr);
    } 

    ~RingQueue()
    {
        sem_destroy(&_consumer_sem);
        sem_destroy(&_productor_sem);
        pthread_mutex_destroy(&_productor_mutex);
        pthread_mutex_destroy(&_consumer_mutex);
    }

    void push(const T& data)
    {
        //首先申请信号量
        sem_wait(&_productor_sem); //申请成功就继续往后执行，申请失败就阻塞，直到成功
        //申请锁资源
        Mutex m(&_productor_mutex); //RAII风格的锁，也就是我们前面封装的一个类

        _rq[_productor_index++]=data; //放数据，同时需要更新下一次进来生产的位置
        _productor_index %= maxsize;  //确保不会越界，因为我们是用数组来模拟环形队列的
        //对消费者信号量V操作
        sem_post(&_consumer_sem);
    }

    void pop(T* data)
    {
        sem_wait(&_consumer_sem);
        Mutex m(&_consumer_mutex);
        
        //拿数据
        *data = _rq[_consumer_index++];
        _consumer_index %= maxsize;
        sem_post(&_productor_sem);
    }

private:
    std::vector<T> _rq;
    sem_t _consumer_sem; //消费者信号量
    sem_t _productor_sem; //生产者信号量
    int _consumer_index; //消费的位置
    int _productor_index; //生产的位置
    pthread_mutex_t _consumer_mutex; //保证消费者之间互斥
    pthread_mutex_t _productor_mutex; //保证生产者之间互斥
};